package top.heathylife.pagehelperx;

import cn.hutool.core.date.SystemClock;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import top.heathylife.pagehelperx.enums.Operator;
import top.heathylife.pagehelperx.other.BusinessException;
import top.heathylife.pagehelperx.wrappers.LambdaEntityWrapper;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * PageHelperX,内存条件查询分页器,用法同mybatis-plus中service.page方法一样,目前实现 eq,like,between,orderByAsc,orderByDesc,如有需要,自行扩展
 * </p>
 *
 * @author maoxiaomeng
 * @date 20230531
 * @see Operator
 */
@Slf4j
public class PageHelperX {

    /**
     * 使用Mybatis-plus的返回对象来进行内存条件查询分页
     *
     * @param page Mybatis-plus的返回对象,请注意page的current,size,以及records都需要有值才能操作
     * @param qw   条件构造器
     * @param <T>  实体泛型
     * @return 条件分页结果
     */
    public static <T> Page<T> page(Page<T> page, LambdaEntityWrapper<T> qw) {
        List<T> data = page.getRecords();
        long current = page.getCurrent();
        long size = page.getSize();
        return page(data, qw, current, size);
    }

    /**
     * 使用自定义实体列表来进行分页,默认分页参数,current=1,size=10
     *
     * @param data 自定义实体列表
     * @param qw   条件构造器
     * @param <T>  实体泛型
     * @return 条件分页结果
     */
    public static <T> Page<T> page(Collection<T> data, LambdaEntityWrapper<T> qw) {
        return page(data, qw, 1, 10);
    }

    /**
     * 使用自定义实体列表来进行分页
     *
     * @param data    自定义实体列表
     * @param qw      条件构造器
     * @param current 当前页
     * @param size    每页大小
     * @param <T>     实体泛型
     * @return 条件分页结果
     */
    public static <T> Page<T> page(Collection<T> data, LambdaEntityWrapper<T> qw, long current, long size) {
        long now = SystemClock.now();
        if (current < 1) {
            current = 1;
        }
        if (size == 0) {
            size = 10;
        }
        Page<T> page = new Page<>(current, size);
        if (ObjectUtil.isEmpty(data)) {
            page.setTotal(0);
            page.setRecords(Collections.emptyList());
            return page;
        }
        if (qw == null) {
            page.setTotal(data.size());
            page.setRecords(new ArrayList<>(data));
            return page;
        }
        log.debug("PageHelperX start=======>");
        log.debug("PageHelperX origin data size :{}", data.size());
        //过滤
        List<Predicate<T>> predicates = qw.predicates();
        if (ObjectUtil.isEmpty(predicates)) {
            log.debug("PageHelperX no filter predicates");
        }
        Stream<T> stream = data.stream().filter(t -> {
            if (ObjectUtil.isNotEmpty(predicates)) {
                return predicates.stream().map(e -> e.test(t)).reduce(Boolean::logicalAnd).orElseThrow(() -> new BusinessException("分页过滤器执行异常"));
            }
            return true;
        });

        List<Comparator<T>> comparators = qw.comparatorList();
        List<T> sortRecords;
        //排序
        if (ObjectUtil.isNotEmpty(comparators)) {
            Comparator<T> orderComparator = comparators.remove(0);
            comparators.forEach(orderComparator::thenComparing);
            sortRecords = stream.sorted(orderComparator).collect(Collectors.toList());
        } else {
            sortRecords = stream.collect(Collectors.toList());
        }
        log.debug("PageHelperX filter processed data size :{}", sortRecords.size());
        //分页
        List<T> records = sortRecords.stream().skip((current - 1) * size).limit(size).collect(Collectors.toList());
        page.setTotal(sortRecords.size());
        page.setRecords(records);
        log.debug("PageHelperX consume:{}ms", SystemClock.now() - now);
        log.debug("PageHelperX end=======>");
        return page;
    }

}
